package com.study.util;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;

/**
 * @author CSDN 流放深圳
 * @description 解密工具类（注意：客户端只有解密，不需要知道加密的逻辑）
 * @create 2024-04-13 15:55
 * 参考链接：https://hutool.cn/docs/#/crypto/非对称加密-AsymmetricCrypto?id=%e4%bb%8b%e7%bb%8d
 * @since 1.0.0
 */
public class LicenceSecurityUtil {

    /**
     * 最大解密长度限制
     */
    public static final int MAX_DECRYPT_LENGTH = 128;

    /**
     * 公钥解密
     *
     * @param str       待解密字符串
     * @param publicKey 公钥
     * @return
     */
    public static String decryptByPublicKey(String str, String publicKey) {
        String result = null;
        try{
            byte[] encoded = Base64.getDecoder().decode(publicKey);
            X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encoded);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicObj = keyFactory.generatePublic(publicKeySpec);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicObj);
            byte[] decryptedBytes = getDecryptResult(str, cipher);
            result = new String(decryptedBytes, "UTF-8");
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 解密的字符串长度不能超过 128 个字节，否则报错，需要分段处理
     * @param str
     * @param cipher
     * @return
     * @throws Exception
     */
    private static byte[] getDecryptResult(String str, Cipher cipher) throws Exception{
        byte[] decryptedBytes = Base64.getDecoder().decode(str.getBytes("UTF-8"));
        int originalLength = decryptedBytes.length;
        int offSet = 0;//偏移量
        byte[] resultBytes = {};
        byte[] cache = {};
        while (originalLength - offSet > 0) {
            if (originalLength - offSet > MAX_DECRYPT_LENGTH) {
                cache = cipher.doFinal(decryptedBytes, offSet, MAX_DECRYPT_LENGTH);
                offSet += MAX_DECRYPT_LENGTH;
            } else {
                cache = cipher.doFinal(decryptedBytes, offSet, originalLength - offSet);
                offSet = originalLength;
            }
            resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
            System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
        }
        return resultBytes;
    }

}